MCU STM32_USBFS_Device固件库使用总结,用片内Flash作小U盘

简介

为了熟悉USB协议,熟悉stm32 usb固件库的结构和使用方法,决定用它做一个u盘,
正点原子开发板上面有例子把sd卡和spi flash作为存储器的u盘,参考这些例子和网上的资料,用内部flash作为存储空间,做了一个小u盘。

stm32内部flash大小为512kbytes,以页为单位,每页2kbytes,256页,起始地址为0800 0000,程序要占用200多kbytes的空间,
所以把最后的256kbytes作为u盘的存储空间,地址为0803 fc00到结束地址。

固件库移植

正点原子例子上面用的usb固件库是2.2版本的,我使用的是最新4.0版本,首先要做的就是先搞好4.0版本的移植。
根据网上资料,官方固件库里的例子,USB固件库的核心协议包括core,init,int,regs,sil,mem这6个C文件,这些文件完成了USB枚举,标准请求的路由等功能,
可以说给USB通信搭建了基础,其它具体的子类协议应用都是在这个基础上搭建起来的。这6个文件不用修改,直接包含到工程中。

使用固件库做mass storage device协议,参考官方固件库里面的例子,需要用到mass_mal,memory,scsi等C文件,直接从固件库的例子里面复制过来就好。
由于固件库给出的例子是运行在特定EVAL开发板上面的,里面有很多预编译语句,把程序搞得比较复杂(为了兼容各个版本的官方开发板),所以要使用在自己的板子上,必须修改优化。
与USB相关的工程文件组织如下:需要修改的文件容我一一道来。

即将添加配图 stm32 usb fs device 固件库使用总结,内部flash作小U盘 - fine_young - fine_young的博客

hw_config这个文件是与usb相关的硬件层驱动,官方有一个set_system函数,我们这里就直接删除掉了;
usb_interrupt_config函数要设置好usb的LP中断wakeup中断;
Get_SerialNum函数是用来获取芯片串行号的,desc,设备描述符中不是也有串行号么,原来是为了防止读取串号错误作的;
如果Get_SerialNum读取固化在芯片中的串号失败了,那么就用desc描述表里面定义的串号。
这个hw_config文件一定要搞好,如果没搞好,电脑根本无法识别。
pwr.c里面有一个函数suspend,挂起,一开始我所有东西都移植好了,但就是无法识别,用jtag跟踪调试发现死在这里面了,于是删除官方给的suspend函数,用正点原子的函数后,可以识别了。
这两个文件是直接和usb对应的硬件相关的,必须搞好,如果无法识别,就调试,看是哪里出了问题。
下面就是和存储器相关的mass_mal.c,memory.c了。

内部flash驱动接口

mass_mal.c封装了所有对存储器的读写操作函数。
为了使用内部flash,直接调用了正点原子flash模拟eeprom试验中对flash的操作函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#define     FLASH_START_ADDR        0x0803fc00   // Flash start address 
#define FLASH_SIZE 0x40000 // 256K大小
#define FLASH_BLOCK_SIZE 0x800 // 2k Bytes per page

uint16_t MAL_Read(uint8_t lun, uint32_t Memory_Offset, uint32_t *Readbuff, uint16_t Transfer_Length)
{
switch (lun)
{
case 0:
STMFLASH_Read(FLASH_START_ADDR+Memory_Offset,(u16 *)Readbuff, Transfer_Length/2);
break;
default:
return MAL_FAIL;
}
return MAL_OK;
}
uint16_t MAL_Write(uint8_t lun, uint32_t Memory_Offset, uint32_t *Writebuff, uint16_t Transfer_Length)
{
switch (lun)
{
case 0:

STMFLASH_Write(FLASH_START_ADDR + Memory_Offset,(u16*)Writebuff,Transfer_Length/2);
break;
default:
return MAL_FAIL;
}
return MAL_OK;
}
uint16_t MAL_GetStatus (uint8_t lun)
{
if (lun == 0)
{
Mass_Block_Count[0] = FLASH_SIZE/FLASH_PAGE_SIZE;
Mass_Block_Size[0] = FLASH_PAGE_SIZE;
Mass_Memory_Size[0] = FLASH_SIZE;
return MAL_OK;
}

return MAL_FAIL;
}

需要注意的是,搞清楚mal操作函数中参数定义是字节数,还是扇区数,将存储器操作函数正确移植,
如果这个文件中的函数有问题,可能会无法格式化U盘。
memory.c中就是改一个uint32_t Data_Buffer[BULK_MAX_PACKET_SIZE 8]; /2K bytes*/
这里BULK_MAX_PACKET_SIZE是512,这样就设置数组大小 为flash的一个页。
还需要注意的是stm32f103_it.C文件中要 参照固件库加上USB中断 处理 函数 。
以上程序修改完成后,主函数完成USB相关的初始化,插上USB线 电脑上就会显示一个247K的小u盘。可以 存储一些 小文件。
做完 这个小u盘之后,对usb协议 和 stm32的usb固件库 有了 一个初步认识,
关于usb命令的散转,标准请求,子类协议等,先看圈圈的usb书,然后对照试验,在stm32的固件库中跟踪usb通信流程,就会对固件库的结构与使用更加明晰。